#pragma once
#include "httplib.h"
#include "data.hpp"
extern cloud::DataManager *_data;
namespace cloud
{
    class Service
    {
    public:
        Service()
        {
            Config *config = Config::GetInstance();
            _ip = config->GetServerIp();
            _port = config->GetServerPort();
            _download_prefix = config->GetDownloadPrefix();
        }
        bool Run()
        {
            _server.Post("/upload", Upload);
            _server.Get("/", ListShow);
            _server.Get("/listshow", ListShow);
            std::string download_url = _download_prefix + ".*";
            _server.Get(download_url, Download);
            _server.listen("0.0.0.0", _port);
        }

    private:
        std::string _ip;
        int _port;
        httplib::Server _server;
        std::string _download_prefix;
        static void Upload(const httplib::Request &req, httplib::Response &res)
        {
            auto ret = req.has_file("file");
            if (ret == false)
            {
                res.status = 400;
                return;
            }
            const auto &file = req.get_file_value("file");
            std::string back_file = Config::GetInstance()->GetBackDir();
            std::string real_path = back_file + FileUtil(file.filename).FileName();
            FileUtil fu(real_path);
            fu.SetContent(file.content);

            BackupInfo info(real_path);

            _data->Insert(info);
            return;
        }
        static std::string TimetoStr(time_t t)
        {
            std::string tmp = std::ctime(&t);
            return tmp;
        }

        static void ListShow(const httplib::Request &req, httplib::Response &res)
        {
            // 1. 获取所有的文件备份信息
            std::vector<BackupInfo> arry;
            _data->GetAll(&arry);
            // 2. 根据所有备份信息，组织html文件数据
            std::stringstream ss;
            ss << "<html><head><title>Download</title></head>";
            ss << "<body><h1>Download</h1><table>";
            for (auto &a : arry)
            {
                ss << "<tr>";
                std::string filename = FileUtil(a._real_path).FileName();
                ss << "<td><a href='" << a._url << "'>" << filename << "</a></td>";
                ss << "<td align='right'>" << TimetoStr(a._mtime) << "</td>";
                ss << "<td align='right'>" << a._fsize / 1024 << "k</td>";
                ss << "</tr>";
            }
            ss << "</table></body></html>";
            res.body = ss.str();
            res.set_header("Content-Type", "text/html");
            res.status = 200;
            return;
        }
        static std::string GetEtag(const BackupInfo&info)
        {
            FileUtil fl(info._real_path);
            std::string res;
            res+=fl.FileName();
            res+="-";
            res+=std::to_string(info._fsize);
            res+="-";
            res+=std::to_string(info._mtime);
            return res;
        }
        static void Download(const httplib::Request &req, httplib::Response &res)
        {
            BackupInfo info;
            _data->GetOneByUrl(req.path, &info);
            if (info._pack_flag)
            {
                // 如果被压缩，解压
                FileUtil fl(info._pack_path);
                fl.UnCompress(info._real_path);
                // 不要忘记删除
                fl.Remove();
                info._pack_flag = false;
                _data->Update(info);
            }
            bool retrans=false;
            std::string old_etag;
            if(req.has_header("If-Range"))
            {
                old_etag=req.get_header_value("If-Range");
                if(old_etag==GetEtag(info))retrans=true;
            }
            FileUtil fl(info._real_path);
            std::string data;
            fl.GetContent(&data);
            res.body = data;
            res.set_header("Accept-Ranges", "bytes");
            res.set_header("ETag", GetEtag(info));
            res.set_header("Content-Type", "application/octet-stream");
            if(retrans)
            res.status = 206;
            else
            res.status = 200;
        }
    };

}